$(function() {
	var game = new Game();
	var $game = $(game);
	var $canvas = $('#canvas');
	var units = {};

	var $combat_log = $('#combat_log');
	var log = function(e, params) {
		var msg = '';
		switch(params.type) {
			case 'character_set':
				msg = params.name + ' set.';
				var you = game.Send({command: 'get_character_settings', name: params.name});
				units[params.name] = new Character(you, $('#character'));
				break;
			case 'damage':
console.log(params.ability);
				msg = params.caster.Name + '\'s ' + params.ability + ' does ' + params.damage + ' damage to ' + params.target.Name + ' (' + params.absorbed + ' absorbed).';
				units[params.target.Name].UpdateHp(params.target.HitPoints());
				break;
			case 'heal':
				msg = params.caster.Name + '\'s ' + params.ability + ' does ' + params.healing + ' healing to ' + params.target.Name + '.';
				break;
			case 'enhancement_added':
				msg = params.enhancement + ' applied to ' + params.caster.Name + '.';
				break;
			case 'buff_added':
				msg = params.caster.Name + ' casts ' + params.ability.Name + ' on ' + params.target.Name + ' (' + params.duration + ' duration).';
				break;
			case 'debuff_added':
				msg = params.caster.Name + ' casts ' + params.ability.Name + ' on ' + params.target.Name + ' (' + params.duration + ' duration).';
				units[params.target.Name].AddDebuff(params);
				break;
			case 'buff_faded':
			case 'debuff_faded':
				msg = params.caster.Name + '\'s ' + params.ability.Name + ' fades from ' + params.target.Name + '.';
				break;
			case 'buff_removed':
			case 'debuff_removed':
				msg = params.caster.Name + '\'s ' + params.ability.Name + ' fades from ' + params.target.Name + '.';
				break;
			case 'ability_queued':
				msg = params.caster.Name + ' queues up ' + params.name + '.';
				units[params.caster.Name].UpdateQueue(params.queue);
				break;
			case 'apply_queue':
				msg = params.caster.Name + ' begins executing a combo' + ((params.ability)?': '+params.ability.Name:'') + '.';
				break;
			case 'casting_ability':
				msg = params.caster.Name + ' begins casting ' + params.ability.Name + '.';
				break;
			case 'enemy_appears':
				msg = params.enemy.Name + ' appears.';
				break;
			default:
				console.log('unknown message recieved:');
				console.log(params);
		}

		$combat_log.prepend($('<p class="' + params.type + '">' + msg + '</p>'));
	};

	$game.bind('message', log);

	var setup_character = function(character, $container) {
		//$('.hp', $container).html(game.Send({command: 'get_hp', name: character.Name}));

		/*

		$character
			.bind('abilityqueuechange', update_queue)
			.bind('useability', function(e, params) {
				if ( params.buff ) {
					log(params.caster.GetName() + ' casts ' + params.buff.Name + ' on ' + params.target.GetName());
				} else if ( params.debuff ) {
					log(params.caster.GetName() + ' casts ' + params.debuff.Name + ' on ' + params.target.GetName());
				} else if ( params.damage ) {
					log(params.caster.GetName() + '\'s ' + params.ability.Name + ' does ' + params.damage + ' to ' + params.target.GetName());
				}
			});

		var $enhancements = $('.enhancements span', $container);
		$character
			.bind('afterdamageapplied', function() {
				$('.hp', $container).html(mob.HitPoints());
			})
			.bind('enhancementsupdated', function() {
				for ( var i=0; i<character.EnhancementCount(); i++ ) {
					var enhancement = character.GetEnhancement(i);
					if ( !enhancement ) continue;
console.log(enhancement);
					var $enhancement = $($enhancements.get(i));
					$enhancement.attr({className: enhancement.Id()}).html(enhancement.Stacks())
				}
			});

		*/
	};

	var Debuff = function(duration, $duration, params) {
		var duration = params.duration;
		var time = new Date();
		time = time.valueOf();
		var expires = time + (duration * 1000);

		var countdown = function() {
			var time = new Date();
			time = time.valueOf();
			$duration.html((expires - time) / 1000);
			setTimeout(countdown, 1000);
		}

		setTimeout(countdown, 1000);

		this.ChangeDuration = function(duration) {
			var time = new Date();
			time = time.valueOf();
			expires = time + (duration * 1000);
		};
	};

	var Character = function(character, $container) {
		var me = this;
		var $hp = $('.hp', $container);
		var $name = $('.name', $container);
		var $abilities = $('.abilities', $container);
		var $enhancements = $('.enhancements', $container);
		var $buffs = $('.buffs', $container);
		var $debuffs = $('.debuffs', $container);
		var $queue = $('.queue', $container);
		var $apply = $('.apply', $container);
		var $queue_abilities;

		$name.html(character.Name);

		this.UpdateHp = function(hp) {
			$hp.html(hp);
		};

		// Queue
		for ( var i = 0; i<character.QueueLength; i++ ) {
			var $q = $('<div><span></span></div>');
			$queue.append($q);
		}
		$queue_abilities = $('div', $queue);

		this.UpdateQueue = function(queue) {
			$queue_abilities.attr({className: ''});
			for ( var i = 0; i<queue.length; i++ ) {
				var ability = queue[i];
				var $ability = $($queue_abilities.get(i));
				$ability.addClass(ability);
			}
		};
		// /Queue

		for ( var ability_key in character.Moves ) {
			var ability = character.Moves[ability_key];
			var $slot = $($('.ability', $abilities).get(ability.Position));
			$slot
				.bind('click', (function(a) {
					return function() {
						game.Send({command: 'queue_ability', ability: a});
					};
				})(ability_key))
				.addClass(ability_key);
		}

		var valid_applies = ['target','self','aoe'];
		for ( var i=0; i<valid_applies.length; i++ ) {
			var apply = valid_applies[i];
			var $apply = $('.apply div.' + apply, $container)
				.bind('click', (function(a) {
					return function() {
						game.Send({command: 'apply_queue', method: a});
					};
				})(apply));
		}

		this.AddDebuff = function(params) {
			var $debuff = $('.' + params.ability.Id, $debuffs);
			var $duration;
			var debuff;
			var duration = params.duration;

			if ( !$debuff.get(0) ) {
				$duration = $('<span/>').html(duration);

				$debuff = $('<div/>')
					.addClass(params.ability.Id)
					.append($duration);

				$debuff
					.appendTo($debuffs);

				var debuff = new Debuff(duration, $duration, params);
				$debuff.data('debuff', debuff);
			} else {
				$duration = $('span', $debuff);
				debuff = $debuff.data('debuff');
				debuff.ChangeDuration(duration);
			}


			/*
			var countdown;
			var timeout;
			countdown = function() {
				
				timeout = setTimeout(countdown, 1000);
				$debuff.data('timeout', timeout);
			};


				timeout = setTimeout(countdown, 1000);
				$debuff.data('timeout', timeout);
				$debuff.data('countdown', countdown);
				timeout = $debuff.data('timeout');
				clearTimeout(timeout);
				timeout = setTimeout(countdown, 1000);
				$debuff.data('timeout', timeout);
				$debuff.html('<span>' + params.duration + '</span>');
			}*/
		};

	};

	game.Send({command: 'set_character', name: 'Maclovio'});
	var enemy = game.GetChar();
	$enemy = $('#templates .enemy').clone().prependTo($canvas);
	units[enemy.Name] = new Character(enemy, $enemy);
	game.Send({command: 'set_target', target: enemy.Name});
});
